from __future__ import division

from concepts.attributes import Attribute, Object, _
from concepts.memoized import memoized


class Calendar(Object):
    starting_year   =_ (None)
    suffix          =_ (None)
    months_per_year =_ (12)
    days_per_month  =_ (30)
    ticks_per_day   =_ (48)
    month_names     =_ (  'I',   'II', 'III', 'IV',  'V',  'VI',
                        'VII', 'VIII',  'IX',  'X', 'XI', 'XII')
    
    year_increases =_ (True)
    
    tick = Attribute(initial = 0, writable = True)
    
    def next_tick(self):
        self.tick += 1
    
    @property
    def ticks_per_months(self):
        return self.ticks_per_day * self.days_per_month
    
    @property
    def ticks_per_year(self):
        return self.ticks_per_month * self.months_per_year
    
    @property
    def days_per_year(self):
        return self.days_per_month * self.months_per_year
    
    @property
    def year_multiplier(self):
        if self.year_increases:
            return +1
        else:
            return -1
    
    @property
    def year(self):
        return self.starting_year + self.year_multiplier * (self.tick // self.ticks_per_year)
    
    @property
    def month(self):
        return (self.tick // self.ticks_per_month) % self.months_per_year + 1
    
    @property
    def day(self):
        return (self.tick // self.ticks_per_day) % self.days_per_month + 1
    
    @property
    def tick_of_day(self):
        return self.tick % self.ticks_per_day
    
    @property
    def total_months(self):
        return (self.tick // self.ticks_per_month) + 1
    
    @property
    def total_days(self):
        return (self.tick // self.ticks_per_day) + 1
    
    def per_year(self, quantity):
        return quantity / self.ticks_per_year
    
    def per_month(self, quantity):
        return quantity / self.ticks_per_month
    
    def per_day(self, quantity):
        return quantity / self.ticks_per_day
    
    def years(self, n):
        return n * self.ticks_per_year
    
    def months(self, n):
        return n * self.ticks_per_month
    
    def days(self, n):
        return n * self.ticks_per_day
    
    @property
    def year_string(self):
        return '%d %s' % (self.year, self.suffix)
    
    @property
    def month_string(self):
        return self.month_names[self.month - 1]
    
    @property
    def day_string(self):
        return '%d%s' % (self.day, self.day_suffix)
    
    @property
    def full_day_string(self):
        return '%s %s' % (self.day_string, self.month_string)
    
    @property
    def day_suffix(self):
        if self.day % 10 == 1 and self.day != 11:
            return 'st'
        elif self.day % 10 == 2 and self.day != 12:
            return 'nd'
        elif self.day % 10 == 3 and self.day != 13:
            return 'rd'
        else:
            return 'th'
    
    @property
    def date(self):
        return (self.year_multiplier * self.year, self.month, self.day)
    
    @property
    def full_month_string(self):
        return '%s in %s' % (self.month_string, self.year_string)
    
    @property
    def date_string(self):
        return '%s of %s in %s' % (self.day_string, self.month_string, self.year_string)
    
    @property
    @memoized
    def ticks_per_month(self):
        return self.ticks_per_day * self.days_per_month
    
    @property
    @memoized
    def ticks_per_year(self):
        return self.ticks_per_month * self.months_per_year
    
    @property
    def is_start_of_year(self):
        return (self._tick % self.ticks_per_year) == 0
    
    @property
    def is_start_of_month(self):
        return (self._tick % self.ticks_per_month) == 0
    
    @property
    def is_start_of_day(self):
        return (self._tick % self.ticks_per_day) == 0
    
    def is_start_of_the_year(self, year):
        return self.is_start_of_year and self.year == year
    
    def is_start_of_the_month(self, month):
        return self.is_start_of_month and self.month == month
    
    def is_start_of_the_day(self, day):
        return self.is_start_of_day and self.day == day
    
    @property
    def is_first_day_of_year(self):
        return self.day == 1 and self.month == 1
    
    @property
    def is_first_day_of_month(self):
        return self.day == 1
    
    def is_first_day_of_the_year(self, year):
        return self.is_first_day_of_year and self.year == year
    
    def is_first_day_of_the_month(self, month):
        return self.is_first_day_of_month and self.month == month
    
    def days_until_start_of_month(self, month):
        months = month - self.month
        
        if months <= 0:
            months += self.months_per_year
        
        return months * self.days_per_month - self.day
